package com.rxt.thermopro.viewmodel

import android.annotation.SuppressLint
import android.util.SparseArray
import androidx.core.util.set
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.app.common.viewmodel.BaseViewModel
import com.app.common.viewmodel.EventLiveData
import com.rxt.thermopro.app.AppContext
import com.rxt.thermopro.app.LocalDataDao
import com.rxt.thermopro.bean.ProfileBean
import com.rxt.thermopro.bean.TempBean
import com.rxt.thermopro.ex.MyLineRegression
import kotlinx.coroutines.*
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.HashMap

class DeviceStatusViewModel : BaseViewModel() {
    //BBQ
    val profileData1: EventLiveData<HashMap<String, ProfileBean>> = EventLiveData()
    val profileData2: EventLiveData<HashMap<String, ProfileBean>> = EventLiveData()
    val profileData3: EventLiveData<HashMap<String, ProfileBean>> = EventLiveData()
    val profileData4: EventLiveData<HashMap<String, ProfileBean>> = EventLiveData()

    val profileListData: EventLiveData<SparseArray<ProfileBean>> = EventLiveData()
    val resetProfile: EventLiveData<Long> = EventLiveData()

    val alarmClock1: MutableLiveData<HashMap<String, String>> = MutableLiveData()
    val alarmClock2: MutableLiveData<HashMap<String, String>> = MutableLiveData()
    val alarmClock3: MutableLiveData<HashMap<String, String>> = MutableLiveData()
    val alarmClock4: MutableLiveData<HashMap<String, String>> = MutableLiveData()

    val profileListTP960Data: EventLiveData<SparseArray<ProfileBean>> = EventLiveData()
    val removeDevice: EventLiveData<HashMap<Long, String>> = EventLiveData()

    fun setProFile(position: Int, bean: ProfileBean, address: String) {
        when (position) {
            1 -> {
                profileData1.value = hashMapOf<String, ProfileBean>().apply {
                    this[address] = bean
                }
                LocalDataDao.INSTANCE.saveProfile1(bean, address)
                LocalDataDao.INSTANCE.updateProfile(bean)

            }
            2 -> {
                profileData2.value = hashMapOf<String, ProfileBean>().apply {
                    this[address] = bean
                }
                LocalDataDao.INSTANCE.saveProfile2(bean, address)
                LocalDataDao.INSTANCE.updateProfile(bean)
            }
            3 -> {
                profileData3.value = hashMapOf<String, ProfileBean>().apply {
                    this[address] = bean
                }
                LocalDataDao.INSTANCE.saveProfile3(bean, address)
                LocalDataDao.INSTANCE.updateProfile(bean)
            }
            4 -> {
                profileData4.value = hashMapOf<String, ProfileBean>().apply {
                    this[address] = bean
                }
                LocalDataDao.INSTANCE.saveProfile4(bean, address)
                LocalDataDao.INSTANCE.updateProfile(bean)
            }
        }
        LocalDataDao.INSTANCE.removeAlarmProfile(position, address)
    }

    fun initProfile() {
        val profile1 = LocalDataDao.INSTANCE.getProfile1()
        val profile2 = LocalDataDao.INSTANCE.getProfile2()
        val profile3 = LocalDataDao.INSTANCE.getProfile3()
        val profile4 = LocalDataDao.INSTANCE.getProfile4()

        val list = SparseArray<ProfileBean>(4)
        list[0] = profile1
        list[1] = profile2
        list[2] = profile3
        list[3] = profile4
        profileListData.postValue(list)
    }

    fun initProfile(deviceType: Int, address: String) {
        when (deviceType) {
            BleMessageViewModel.DEVICE_TYPE_TP960 -> {
                val profile1 = LocalDataDao.INSTANCE.getProfile1(address)
                val profile2 = LocalDataDao.INSTANCE.getProfile2(address)

                val list = SparseArray<ProfileBean>(2)
                list[0] = profile1
                list[1] = profile2
                profileListTP960Data.postValue(list)
            }
            BleMessageViewModel.DEVICE_TYPE_BBQ -> {
                val profile1 = LocalDataDao.INSTANCE.getProfile1(address)
                val profile2 = LocalDataDao.INSTANCE.getProfile2(address)
                val profile3 = LocalDataDao.INSTANCE.getProfile3(address)
                val profile4 = LocalDataDao.INSTANCE.getProfile4(address)

                val list = SparseArray<ProfileBean>(4)
                list[0] = profile1
                list[1] = profile2
                list[2] = profile3
                list[3] = profile4
                profileListData.postValue(list)
            }
            BleMessageViewModel.DEVICE_TYPE_GRILL -> {
                val profile1 = LocalDataDao.INSTANCE.getProfile1(address)
                val profile2 = LocalDataDao.INSTANCE.getProfile2(address)

                val list = SparseArray<ProfileBean>(2)
                list[0] = profile1
                list[1] = profile2
                profileListData.postValue(list)
            }
        }
    }

    fun refreshProfile(mAddress: String, mDeviceType: Int, mPosition: Int) {
        viewModelScope.launch {
            withContext(Dispatchers.Main) {
                initProfile(mDeviceType, mAddress)
                delay(500)
                when (mPosition) {
                    1 -> {
                        profileData1.postValue(hashMapOf<String, ProfileBean>().apply {
                            this[mAddress] = LocalDataDao.INSTANCE.getProfile1(mAddress)
                        })
                    }
                    2 -> {
                        profileData2.postValue(hashMapOf<String, ProfileBean>().apply {
                            this[mAddress] = LocalDataDao.INSTANCE.getProfile2(mAddress)
                        })
                    }
                    3 -> {
                        profileData3.postValue(hashMapOf<String, ProfileBean>().apply {
                            this[mAddress] = LocalDataDao.INSTANCE.getProfile3(mAddress)
                        })
                    }
                    4 -> {
                        profileData4.postValue(hashMapOf<String, ProfileBean>().apply {
                            this[mAddress] = LocalDataDao.INSTANCE.getProfile4(mAddress)
                        })
                    }
                }
                delay(300)
                resetProfile.value = System.currentTimeMillis()
            }
        }
    }

    private var blockWorking1 = hashMapOf<String, Boolean>()
    private var blockWorking2 = hashMapOf<String, Boolean>()
    private var blockWorking3 = hashMapOf<String, Boolean>()
    private var blockWorking4 = hashMapOf<String, Boolean>()

    var blockText1 = ""
    var blockText2 = ""
    var blockText3 = ""
    var blockText4 = ""
    var blockTime1 = hashMapOf<String, String>()
    var blockTime2 = hashMapOf<String, String>()
    var blockTime3 = hashMapOf<String, String>()
    var blockTime4 = hashMapOf<String, String>()

    fun startAlarmClock(address: String, position: Int, blockTime: String, blockText: String) {
        viewModelScope.launch {
            withContext(Dispatchers.IO) {
                when (position) {
                    0 -> {
                        blockWorking1[address] = true
                        blockText1 = blockText
                        LocalDataDao.INSTANCE.saveAlarmText1(blockText1, address)
                        timeDown(address, position, blockTime, alarmClock1)
                    }
                    1 -> {
                        blockWorking2[address] = true
                        blockText2 = blockText
                        LocalDataDao.INSTANCE.saveAlarmText2(blockText2, address)
                        timeDown(address, position, blockTime, alarmClock2)
                    }
                    2 -> {
                        blockWorking3[address] = true
                        blockText3 = blockText
                        LocalDataDao.INSTANCE.saveAlarmText3(blockText3, address)
                        timeDown(address, position, blockTime, alarmClock3)
                    }
                    3 -> {
                        blockWorking4[address] = true
                        blockText4 = blockText
                        LocalDataDao.INSTANCE.saveAlarmText4(blockText4, address)
                        timeDown(address, position, blockTime, alarmClock4)
                    }
                }
            }
        }
    }

    private suspend fun timeDown(
        address: String,
        position: Int,
        blockString: String,
        blockEventData: MutableLiveData<HashMap<String, String>>
    ) {
        blockEventData.postValue(hashMapOf<String, String>().apply {
            this[address] = blockString
        })
        val h = blockString.split(":")[0]
        val m = blockString.split(":")[1]
        val s = blockString.split(":")[2]
        var time = h.toInt() * 60 * 60 + m.toInt() * 60 + s.toInt()
        println("==========> time=$time")
        while (isBlockWorking(position, address) && time > 0) {
            delay(1000)
            time -= 1
            val newH = time / (60 * 60)
            val newM = time % (60 * 60) / 60
            val newS = time % 60
            val newMStr = if (newM < 10) "0$newM" else "$newM"
            val newSStr = if (newS < 10) "0$newS" else "$newS"
            withContext(Dispatchers.Main) {
                blockEventData.value = hashMapOf<String, String>().apply {
                    this[address] = "$newH:$newMStr:$newSStr"
                }
                if (time == 0) {
                    when (position) {
                        0 -> {
                            blockWorking1[address] = false
                        }
                        1 -> {
                            blockWorking2[address] = false
                        }
                        2 -> {
                            blockWorking3[address] = false
                        }
                        3 -> {
                            blockWorking4[address] = false
                        }
                        else -> blockWorking1[address] = false
                    }
                    blockEventData.value = hashMapOf<String, String>().apply {
                        this[address] = ""
                    }
                    if (LocalDataDao.INSTANCE.isAlarm(address) ||
                        LocalDataDao.INSTANCE.isAlarmVibration(address)) {
                        AppContext.get().alarm(position, address)
                    }
                }
                println("==========> newTime=$newH:$newMStr:$newSStr")
            }
        }
    }

    fun isBlockWorking(position: Int, address: String): Boolean {
        return when (position) {
            0 -> {
                blockWorking1[address] ?: false
            }
            1 -> {
                blockWorking2[address] ?: false
            }
            2 -> {
                blockWorking3[address] ?: false
            }
            3 -> {
                blockWorking4[address] ?: false
            }
            else -> false
        }
    }

    fun stopBlockWorking(address: String, position: Int, blockTime: String, blockText: String) {
        println("===========>stopBlockWorking=$blockText    $blockTime")
        viewModelScope.launch {
            when (position) {
                0 -> {
                    blockText1 = blockText
                    blockWorking1[address] = false
                    delay(1000)
                    blockTime1[address] = blockTime
                    alarmClock1.postValue(hashMapOf<String, String>().apply {
                        this[address] = "stop"
                    })
                }
                1 -> {
                    blockText2 = blockText
                    blockWorking2[address] = false
                    delay(1000)
                    blockTime2[address] = blockTime
                    alarmClock2.postValue(hashMapOf<String, String>().apply {
                        this[address] = "stop"
                    })
                }
                2 -> {
                    blockText3 = blockText
                    blockWorking3[address] = false
                    delay(1000)
                    blockTime3[address] = blockTime
                    alarmClock3.postValue(hashMapOf<String, String>().apply {
                        this[address] = "stop"
                    })
                }
                3 -> {
                    blockText4 = blockText
                    blockWorking4[address] = false
                    delay(1000)
                    blockTime4[address] = blockTime
                    alarmClock4.postValue(hashMapOf<String, String>().apply {
                        this[address] = "stop"
                    })
                }
            }
        }
    }

    fun resetBlockWorking(position: Int, address: String) {
        println("======>  resetBlockWorking  position=$position  address=$address ")
        viewModelScope.launch {
            when (position) {
                0 -> {
                    blockWorking1[address] = false
                    delay(1000)
                    blockText1 = ""
                    blockTime1[address] = ""
                    LocalDataDao.INSTANCE.resetAlarmText1(address)
                    alarmClock1.postValue(hashMapOf<String, String>().apply {
                        this[address] = "0:0:0"
                    })
                }
                1 -> {
                    blockWorking2[address] = false
                    delay(1000)
                    blockText2 = ""
                    blockTime2[address] = ""
                    LocalDataDao.INSTANCE.resetAlarmText2(address)
                    alarmClock2.postValue(hashMapOf<String, String>().apply {
                        this[address] = "0:0:0"
                    })
                }
                2 -> {
                    blockWorking3[address] = false
                    delay(1000)
                    blockText3 = ""
                    blockTime3[address] = ""
                    LocalDataDao.INSTANCE.resetAlarmText3(address)
                    alarmClock3.postValue(hashMapOf<String, String>().apply {
                        this[address] = "0:0:0"
                    })
                }
                3 -> {
                    blockWorking4[address] = false
                    delay(1000)
                    blockText4 = ""
                    blockTime4[address] = ""
                    LocalDataDao.INSTANCE.resetAlarmText4(address)
                    alarmClock4.postValue(hashMapOf<String, String>().apply {
                        this[address] = "0:0:0"
                    })
                }
            }
        }

    }


    val needTimeClock1: EventLiveData<HashMap<String, String>> = EventLiveData()
    val needTimeClock2: EventLiveData<HashMap<String, String>> = EventLiveData()
    val needTimeClock3: EventLiveData<HashMap<String, String>> = EventLiveData()
    val needTimeClock4: EventLiveData<HashMap<String, String>> = EventLiveData()

    private var blockTimeWorking1 = hashMapOf<String, Boolean>()
    private var blockTimeWorking2 = hashMapOf<String, Boolean>()
    private var blockTimeWorking3 = hashMapOf<String, Boolean>()
    private var blockTimeWorking4 = hashMapOf<String, Boolean>()

    private var blockJob = hashMapOf<String, Job>()
    private var timeCacheMap = linkedMapOf<String, Int>()

    fun startTimeClock(address: String, position: Int, blockTime: String) {
        println("123-> startTimeClock   position=$position  blockTime=$blockTime  address=$address ")
        val clockJob = viewModelScope.launch {
            withContext(Dispatchers.IO) {
                val newAddress = address + "_" + position
                when (position) {
                    0 -> {
                        if (blockTimeWorking1[address] == true) {
                            val h = blockTime.split(":")[0]
                            val m = blockTime.split(":")[1]
                            val s = blockTime.split(":")[2]
                            timeCacheMap[newAddress] =
                                h.toInt() * 60 * 60 + m.toInt() * 60 + s.toInt()
                        } else {
                            blockTimeWorking1[address] = true
                            timeDown1(address, position, blockTime, needTimeClock1)
                        }
                    }
                    1 -> {
                        if (blockTimeWorking2[address] == true) {
                            val h = blockTime.split(":")[0]
                            val m = blockTime.split(":")[1]
                            val s = blockTime.split(":")[2]
                            timeCacheMap[newAddress] =
                                h.toInt() * 60 * 60 + m.toInt() * 60 + s.toInt()
                        } else {
                            blockTimeWorking2[address] = true
                            timeDown1(address, position, blockTime, needTimeClock2)
                        }
                    }
                    2 -> {
                        if (blockTimeWorking3[address] == true) {
                            val h = blockTime.split(":")[0]
                            val m = blockTime.split(":")[1]
                            val s = blockTime.split(":")[2]
                            timeCacheMap[newAddress] =
                                h.toInt() * 60 * 60 + m.toInt() * 60 + s.toInt()
                        } else {
                            blockTimeWorking3[address] = true
                            timeDown1(address, position, blockTime, needTimeClock3)
                        }
                    }
                    3 -> {
                        if (blockTimeWorking4[address] == true) {
                            val h = blockTime.split(":")[0]
                            val m = blockTime.split(":")[1]
                            val s = blockTime.split(":")[2]
                            timeCacheMap[newAddress] =
                                h.toInt() * 60 * 60 + m.toInt() * 60 + s.toInt()
                        } else {
                            blockTimeWorking4[address] = true
                            timeDown1(address, position, blockTime, needTimeClock4)
                        }
                    }
                }
            }
        }
        blockJob[address] = clockJob
    }

    fun updateBlockTime(address: String, position: Int, newTime: String) {
        println("123-> updateBlockTime   position=$position  blockTime=$newTime  address=$address ")
        val h = newTime.split(":")[0]
        val m = newTime.split(":")[1]
        val s = newTime.split(":")[2]
        val time = h.toInt() * 60 * 60 + m.toInt() * 60 + s.toInt()
        val newAddress = address + "_" + position
        timeCacheMap[newAddress] = time
    }

    private suspend fun timeDown1(
        address: String,
        position: Int,
        blockString: String,
        blockEventData: EventLiveData<HashMap<String, String>>
    ) {
        blockEventData.postValue(hashMapOf<String, String>().apply {
            this[address] = blockString
        })
        val h = blockString.split(":")[0]
        val m = blockString.split(":")[1]
        val s = blockString.split(":")[2]
        var time = h.toInt() * 60 * 60 + m.toInt() * 60 + s.toInt()
        val newAddress = address + "_" + position
        timeCacheMap[newAddress] = time

        while (isBlockTimeWorking(position, address) && (timeCacheMap[newAddress] ?: 0) > 0) {
            delay(1000)
            println("==========> timeDown1  position=$position  address=$address  time=$time")
            time = timeCacheMap[newAddress] ?: 0
            time -= 1
            timeCacheMap[newAddress] = time
            val newH = time / (60 * 60)
            val newM = time % (60 * 60) / 60
            val newS = time % 60
            val newMStr = if (newM < 10) "0$newM" else "$newM"
            val newSStr = if (newS < 10) "0$newS" else "$newS"
            withContext(Dispatchers.Main) {
                blockEventData.value = hashMapOf<String, String>().apply {
                    this[address] = "$newH:$newMStr:$newSStr"
                }
                if (time == 0) {
                    when (position) {
                        0 -> {
                            blockTimeWorking1[address] = false
                        }
                        1 -> {
                            blockTimeWorking2[address] = false
                        }
                        2 -> {
                            blockTimeWorking3[address] = false
                        }
                        3 -> {
                            blockTimeWorking4[address] = false
                        }
                        else -> blockTimeWorking1[address] = false
                    }
                    blockEventData.value = hashMapOf<String, String>().apply {
                        this[address] = ""
                    }
                }
                println("==========> newTime=$newH:$newMStr:$newSStr")
            }
        }
    }

    fun isBlockTimeWorking(position: Int, address: String): Boolean {
        return when (position) {
            0 -> {
                blockTimeWorking1[address] ?: false
            }
            1 -> {
                blockTimeWorking2[address] ?: false
            }
            2 -> {
                blockTimeWorking3[address] ?: false
            }
            3 -> {
                blockTimeWorking4[address] ?: false
            }
            else -> false
        }
    }

    fun stopBlockTimeWorking(address: String, position: Int, blockTime: String) {
        viewModelScope.launch {
            when (position) {
                0 -> {
                    blockTimeWorking1[address] = false
                    delay(1000)
                    needTimeClock1.postValue(hashMapOf<String, String>().apply {
                        this[address] = "0:0:0"
                    })
                }
                1 -> {
                    blockTimeWorking2[address] = false
                    delay(1000)
                    needTimeClock2.postValue(hashMapOf<String, String>().apply {
                        this[address] = "0:0:0"
                    })
                }
                2 -> {
                    blockTimeWorking3[address] = false
                    delay(1000)
                    needTimeClock3.postValue(hashMapOf<String, String>().apply {
                        this[address] = "0:0:0"
                    })
                }
                3 -> {
                    blockTimeWorking4[address] = false
                    delay(1000)
                    needTimeClock4.postValue(hashMapOf<String, String>().apply {
                        this[address] = "0:0:0"
                    })
                }
            }
        }
    }


    fun resetBlockTimeWorking(position: Int, address: String) {
        println("123-> resetBlockTimeWorking   position=$position address=$address ")
        blockJob[address]?.cancel()
        viewModelScope.launch {
            when (position) {
                0 -> {
                    blockTimeWorking1[address] = false
                    delay(1100)
                    needTimeClock1.postValue(hashMapOf<String, String>().apply {
                        this[address] = ""
                    })
                }
                1 -> {
                    blockTimeWorking2[address] = false
                    delay(1100)
                    needTimeClock2.postValue(hashMapOf<String, String>().apply {
                        this[address] = ""
                    })
                }
                2 -> {
                    blockTimeWorking3[address] = false
                    delay(1100)
                    needTimeClock3.postValue(hashMapOf<String, String>().apply {
                        this[address] = ""
                    })
                }
                3 -> {
                    blockTimeWorking4[address] = false
                    delay(1100)
                    needTimeClock4.postValue(hashMapOf<String, String>().apply {
                        this[address] = ""
                    })
                }
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        blockTimeWorking1.keys.forEach {
            blockTimeWorking1[it] = false
        }
        blockTimeWorking2.keys.forEach {
            blockTimeWorking2[it] = false
        }
        blockTimeWorking3.keys.forEach {
            blockTimeWorking3[it] = false
        }
        blockTimeWorking4.keys.forEach {
            blockTimeWorking4[it] = false
        }
    }


    /**
     * 预测时间
     */
    @SuppressLint("SetTextI18n")
    fun computeNeedTime(
        address: String,
        probeIndex: Int,
        targetTemp: Double,
        tempListCache: MutableList<TempBean>
    ) {
        if (tempListCache.size >= 2) {
            val lineRegression = MyLineRegression()
            val list = tempListCache
            val xTime = list.map { it.tempTime.toDouble() }.toMutableList()
            val yTemp = list.map { it.tempNum1.toDouble() }.toMutableList()

            println("====> lineRegression x[]=$xTime   y[]=$yTemp")
            val map = lineRegression.lineRegression(
                xTime.toDoubleArray(),
                yTemp.toDoubleArray()
            )
            println("====> lineRegression=$map")
            val a = map["a"]!!
            val b = map["b"]!!
            val r = map["r"]!!
            val x = (targetTemp - b) / a
            val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
            val date = Date()
//            date.time = x.toLong() + firstTime.toLong()
//            val fTime = dateFormat.format(date)
//            val sTime = (x.toLong() + firstTime.toLong() - System.currentTimeMillis()) / 1000

            date.time = x.toLong()
            val fTime = dateFormat.format(date)
            val sTime = (x.toLong() - System.currentTimeMillis()) / 1000
            if (sTime > 0 && sTime < 99 * 60 * 60) {
                val newH = sTime / (60 * 60)
                val newM = sTime % (60 * 60) / 60
                val newS = sTime % 60
                val newTime = "${if (newH < 10) "0$newH" else newH.toString()}:${
                    if (newM < 10) "0$newM"
                    else newM.toString()
                }:${if (newS < 10) "0$newS" else newS.toString()}"
                startTimeClock(
                    address,
                    0,
                    newTime
                )
            }
//            else {
//                startTimeClock(
//                    address,
//                    0,
//                    "02:23:13"
//                )
//            }
            println("====> 预测时间=$x   $fTime     probeIndex=$probeIndex")
        } else {
            println("====> cacheHistoryTemp is empty")
        }
    }

}